﻿/*
 *Author: Jeff Liu 
 *
 *Under MIT License
 *jebberwocky@gmail.com
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CtpGglMap;
using CtpGglMap.Impl;
using System.IO;
using CtpGglMap.Core;
using CtpGglMap.Util;
using CtpGglMap.Plus;

namespace CtpGglMap.Windows.Control
{
    public partial class GStaticMap : UserControl
    {
        public delegate void OnGMarkerClickDelegate(GMarker marker, Point point);
        [Category("Action")]
        [Description("Fires when the GMarker is clicked.")]
        public event OnGMarkerClickDelegate OnGMarkerClick;

        public delegate void OnGPathClickDelegate(GPath path, List<Point> points);
        [Category("Action")]
        [Description("Fires when the GPath is clicked.")]
        public event OnGPathClickDelegate OnGPathClick;

        public delegate void OnGMapNotDefinedDelegate(StaticGMap map);
        [Description("Fires when the StaticGMap return nothing")]
        public event OnGMapNotDefinedDelegate OnGMapNotDefined;

        public delegate void OnGMapMarkerMouseOverDelegate(GMarker marker, Point point);
        [Category("Action")]
        [Description("Fires when the cursor over the GMarker")]
        public event OnGMapMarkerMouseOverDelegate OnGMarkerMouseOver;

        public delegate void OnGMapMarkerMouseOutDelegate();
        [Category("Action")]
        [Description("Fires when the cursor out of the GMarker")]
        public event OnGMapMarkerMouseOutDelegate OnGMarkerMouseOut;

        private Point LastCursorLocation;

        /// <summary>
        /// Constructor
        /// </summary>
        public GStaticMap()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Fetch image from google service
        /// </summary>
        private void LoadMap()
        {
            if (_gmap != null)
            {
                Stream stream = null;
                try
                {
                    if (_gmap.GetType() == typeof(StaticGMapPlus))
                    {
                        _gimage = ((StaticGMapPlus)_gmap).FetchBitmap();
                        if (_gimage == null && OnGMapNotDefined != null)
                            OnGMapNotDefined(_gmap);
                    }
                    else if (_gmap.GetType() == typeof(StaticGMap))
                    {
                        stream = Gmap.Fetch();
                        if (stream != null)
                            _gimage = System.Drawing.Image.FromStream(stream);
                        else
                            if (OnGMapNotDefined != null)
                                OnGMapNotDefined(_gmap);
                    }
                }
                catch (System.Exception e)
                {
                    throw e;
                }
                finally
                {
                    if (stream != null)
                        stream.Dispose();
                }
            }
            this.MapPictureBox.Image = _gimage;
        }

        /// <summary>
        /// when click on particular gmarker, OnGMarkerClick event trigger
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MapPictureBox_Click(object sender, EventArgs e)
        {
            Point point = this.MapPictureBox.PointToClient(Cursor.Position);
            if (_gmap != null)
            {
                foreach (IMapItem item in _gmap.GetItems())
                {
                    if (item != null && 
                        (item.GetType().IsSubclassOf(typeof(GMarker)) || item.GetType() == typeof(GMarker))
                        )
                    {
                        GMarker marker = item as GMarker;
                        if (this.IsInArea(point, marker))
                            if (OnGMarkerClick != null)
                                OnGMarkerClick(marker, point);
                    }
                }
            }
        }

        private const int GMARKER_AREA_RADIUS =14;
        private const int PINHEAD_OFFSET = 13;

        /// <summary>
        /// is point in Gmarker
        /// </summary>
        /// <param name="p"></param>
        /// <param name="marker"></param>
        /// <returns></returns>
        private bool IsInArea(Point p, GMarker marker)
        {
            PixelXY gmarkerCenter = marker.PixelXY;
            return (Math.Pow((double)(p.X - gmarkerCenter.X) ,2) + 
                Math.Pow((double)(p.Y - (gmarkerCenter.Y-PINHEAD_OFFSET)) ,2)) <= 
                Math.Pow((double)GMARKER_AREA_RADIUS,2) ;
        }

        /// <summary>
        /// changing cursor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MapPictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            Point point = this.MapPictureBox.PointToClient(Cursor.Position);
            if (point == this.LastCursorLocation)
                return;
            this.LastCursorLocation = point;
            if (_gmap != null)
            {
                foreach (IMapItem item in _gmap.GetItems())
                {
                    if (item != null &&
                        (item.GetType().IsSubclassOf(typeof(GMarker)) || item.GetType() == typeof(GMarker))
                        )
                    {
                        GMarker marker = item as GMarker;
                        if (this.IsInArea(point, marker))
                        {
                            this.Cursor = Cursors.Hand;
                            if (OnGMarkerMouseOver != null)
                                OnGMarkerMouseOver(marker, point);
                            return;
                        }
                        else
                        {
                            this.Cursor = Cursors.Default;
                            if (OnGMarkerMouseOut != null)
                                OnGMarkerMouseOut();
                        }
                    }
                }
            }
        }
    }

    //TODO using this Event Argument for event
    public class GStaticMapEventArgs : EventArgs
    {
        public GStaticMapEventArgs(Point point)
        {
            _point = point;
        }
        private Point _point;
        public Point Point { get { return _point; } }
    }
}
